package com.fourth.service.impl;

import cn.hutool.core.util.StrUtil;
import com.fourth.dto.Result;
import com.fourth.dto.UserDTO;
import com.fourth.entity.BankCard;
import com.fourth.entity.User;
import com.fourth.enums.ResultCode;
import com.fourth.mapper.BankCardMapper;
import com.fourth.mapper.UserMapper;
import com.fourth.service.IAccountStatementService;
import com.fourth.service.IBankCardService;
import com.fourth.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fourth.util.UserHolder;
import com.fourth.util.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;

import static com.fourth.enums.ResultCode.TRANSFER_TARGET_ERROR;
import static com.fourth.util.Constants.PHONE_REGEX;
import static com.fourth.util.Constants.SUCCESS_CODE;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author 邓建波
 * @since 2022-08-04
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Resource
    private BankCardMapper bankCardMapper;
    @Resource
    private IBankCardService iBankCardService;
    @Resource
    private UserMapper userMapper;
    @Resource
    private IAccountStatementService iAccountStatementService;

    /**
     *  提现操作
    * @author 邓建波
    * @date 2022/8/5 17:42
    */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public Result withdrawal(BigDecimal amount, String cardId, String payPassword) {
        // TODO 校验
        final Result result = checkOption(amount, cardId, payPassword);
        if(!result.getCode().equals(SUCCESS_CODE)){
            return result;
        }
        // TODO 1.获取当前用户userId
        UserDTO user = UserHolder.getUser();
        Long userId = user.getUserId();
        // TODO 2.判断支付密码payPassword是否正确
        User one = query().select("user_pay_password","balance","user_phone").eq("user_id", userId).one();
        if(!payPassword.equals(one.getUserPayPassword())){
            //TODO 2.1 如果不正确返回，密码错误
            return new Result(ResultCode.PASSWORD_ERROR);
        }
        // TODO 3.查询当前用户余额（balance）
        // TODO 4.判断当前balance 与 amount 大小
        if(one.getBalance().compareTo(amount) < 0){
            // TODO 4.1 balance < amount 返回余额不足
            iAccountStatementService.insertRecord(userId,"2",amount,2,
                    one.getUserPhone(), user.getUserName(),cardId,
                    user.getUserName(), "余额不足");
            return new Result(ResultCode.ACCOUNT_BALANCE_NOT_ENOUGH);
        }
        // TODO 5.扣减虚拟账户余额
        final boolean update = update().set("balance", one.getBalance().subtract(amount)).eq("user_id", userId).update();
        if (!update){
            log.debug("user表发生异常");
            throw new BusinessException(ResultCode.MYSQL_ERROR);
        }
        // TODO 6.增加银行卡余额
        final boolean balance = bankCardMapper.addCardBalance(cardId, amount);
        if(!balance){
            log.debug("银行系统异常");
            throw new BusinessException(ResultCode.BANK_SYSTEM_ERROR);
        }
        // TODO 7. 插入流水帐记录
        final Boolean insertRecord = iAccountStatementService.insertRecord(userId, "2", amount, 1,
                one.getUserPhone(), user.getUserName(), cardId,
                user.getUserName(), "提现到账");
        if(!insertRecord){
            log.debug("插入流水账目表错误");
            throw new BusinessException(ResultCode.MYSQL_ERROR);
        }
        // TODO 8.提现成功
        return Result.ok("提现成功");
    }

    /**
     *  充值操作
     * @author 刘晨光
     * @date 2022/8/5 17:42
     */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public Result recharge(BigDecimal amount, String cardId, String payPassword) {
        // TODO 校验
        final Result result = checkOption(amount, cardId, payPassword);
        if(!result.getCode().equals(SUCCESS_CODE)){
            return result;
        }
        // TODO 1.获取当前用户userId
        UserDTO user = UserHolder.getUser();
        Long userId = user.getUserId();
        // TODO 2.判断支付密码payPasswrod是否正确
        User one = query().select("user_pay_password","balance","user_phone").eq("user_id", userId).one();
        if(!payPassword.equals(one.getUserPayPassword())){
            //TODO 2.1 如果不正确返回，密码错误
            return new Result(ResultCode.PASSWORD_ERROR);
        }
        // TODO 3.查询当前银行卡余额（cardBalance）
        BankCard card = iBankCardService.query().select("card_balance").eq("card_id", cardId).one();
        // TODO 4.判断当前cardBalance 与 amount 大小
        if(card.getCardBalance().compareTo(amount)<0){
            // TODO 4.1 cardBalance < amount 返回余额不足
            iAccountStatementService.insertRecord(userId,"1",amount,2,
                    cardId, user.getUserName(), one.getUserPhone(),
                    user.getUserName(), "银行卡余额不足");
            return new Result(ResultCode.BANK_CARD_BALANCE_NOT_ENOUGH);
        }
        // TODO 5.增加账户余额
        final boolean update = update().set("balance", one.getBalance().add(amount)).eq("user_id", userId).update();
        if (!update){
            log.debug("user表发生异常");
            throw new BusinessException(ResultCode.MYSQL_ERROR);
        }
        // TODO 6.扣除银行卡余额
        final boolean reduceBalance = bankCardMapper.reduceBalance(cardId, amount);
        if(!reduceBalance){
            log.debug("bank_card表异常");
            throw new BusinessException(ResultCode.MYSQL_ERROR);
        }
        // TODO 插入流水账单
        final Boolean insertRecord = iAccountStatementService.insertRecord(userId, "1", amount, 1,
                cardId, user.getUserName(), one.getUserPhone(),
                user.getUserName(), "充值到账");
        if (!insertRecord){
            log.debug("插入流水账目表错误");
            throw new BusinessException(ResultCode.MYSQL_ERROR);
        }
        // TODO 8.充值成功
        return Result.ok("充值成功");
    }

    /**
     *  转账操作
     * @author 王丽丽
     * @date 2022/8/5 17:42
     */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public Result transferAccounts(BigDecimal transferMoney, String transferPhone, String payPassword, String transferName) {
        // TODO 校验
        if(isPhoneInvalid(transferPhone)){
            return new Result(ResultCode.PHONE_NUMBER_ERROR);
        }
        // TODO 1.获取当前用户userId
        UserDTO user = UserHolder.getUser();
        Long userId = user.getUserId();
        // TODO 2.判断支付密码payPassword是否正确
        User one = query().select("user_pay_password","balance","user_phone").eq("user_id", userId).one();
        if(!payPassword.equals(one.getUserPayPassword())){
            //TODO 2.1 如果不正确返回，密码错误
            return new Result(ResultCode.PASSWORD_ERROR);
        } else if(one.getUserPhone().equals(transferPhone)){
            return Result.fail("请不要给自己转账");
        }
            //TODO 2.1查询收款账户信息
        final User targetUser = query().select("user_id,user_name").eq("user_phone", transferPhone).eq("user_name",transferName).one();
        if (targetUser == null){
            return new Result(TRANSFER_TARGET_ERROR);
        }
        // TODO 3.查询当前用户余额（balance）
        // TODO 4.判断当前balance 与 tradeMoney 大小
        if(one.getBalance().compareTo(transferMoney) < 0){
            // TODO 4.1 balance < tradeMoney 返回余额不足
            iAccountStatementService.insertRecord(userId,"3",transferMoney,2,
                    one.getUserPhone(), user.getUserName(),transferPhone,
                    targetUser.getUserName(), "账户余额不足");
            return new Result(ResultCode.ACCOUNT_BALANCE_NOT_ENOUGH);
        }
        // TODO 5.扣减付款账户余额
        final boolean update = update().set("balance", one.getBalance().subtract(transferMoney)).eq("user_id", userId).update();
        if (!update){
            log.debug("user表发生异常");
            throw new BusinessException(ResultCode.MYSQL_ERROR);
        }
        // TODO 6.增加收款账户余额
        boolean add = userMapper.addTransfer(transferPhone,transferMoney);
        if(!add){
            log.debug("user表发生异常");
            throw new BusinessException(ResultCode.MYSQL_ERROR);
        }
        // TODO 7.插入账目流水
        final Boolean insertRecord = iAccountStatementService.insertRecord(userId, "3", transferMoney, 1,
                one.getUserPhone(), user.getUserName(), transferPhone,
                targetUser.getUserName(), "转账成功");
        if (!insertRecord){
            log.debug("插入流水账目表错误");
            throw new BusinessException(ResultCode.MYSQL_ERROR);
        }
        // TODO 8.转账成功
        return Result.ok("转账成功");
    }

    /**
     * 校验手机号码是否正确
     * @param phone 手机号码
     * @return true or false
     */
    private boolean isPhoneInvalid(String phone){
        if (StrUtil.isBlank(phone)) {
            return true;
        }
        return !phone.matches(PHONE_REGEX);
    }

    /**
     * 校验
     * @param amount 转账金额
     * @param cardId 银行卡号
     * @param payPassword 密码
     * @return Result
     */
    private Result checkOption(BigDecimal amount, String cardId, String payPassword){
        // TODO 1.校验
        if (amount.compareTo(new BigDecimal(0)) < 0){
            return Result.fail("转账金额错误");
        } else if(StrUtil.isBlank(cardId) || cardId.length() != 16){
            return Result.fail("银行卡号错误");
        } else if(StrUtil.isBlank(payPassword) || payPassword.length() < 4) {
            return Result.fail("密码错误");
        }
        return Result.ok();
    }
}
